# jlink_operations.py (JLink 操作模块)

import ctypes
import os
import sys
from enum import Enum
import io


class JLinkException(Exception):
    pass

class JTAG_ID_DATA(ctypes.Structure):
    _fields_ = [
        ("NumDevices", ctypes.c_int),            # 设备数量
        ("ScanLen", ctypes.c_ushort),            # 扫描链总位数
        ("aId", ctypes.c_uint * 3),              # JTAG ID 数组
        ("aScanLen", ctypes.c_ubyte * 3),        # 扫描链长度数组
        ("aIrRead", ctypes.c_ubyte * 3),         # 从指令寄存器读取的数据
        ("aScanRead", ctypes.c_ubyte * 3),       # 从扫描链读取的数据
    ]

# 定义枚举
class JLINKARM_CM4_REG(Enum):
    JLINKARM_CM4_REG_R0 = 0    # Index  0
    JLINKARM_CM4_REG_R1 = 1    # Index  1
    JLINKARM_CM4_REG_R2 = 2    # Index  2
    JLINKARM_CM4_REG_R3 = 3    # Index  3
    JLINKARM_CM4_REG_R4 = 4    # Index  4
    JLINKARM_CM4_REG_R5 = 5    # Index  5
    JLINKARM_CM4_REG_R6 = 6    # Index  6
    JLINKARM_CM4_REG_R7 = 7    # Index  7
    JLINKARM_CM4_REG_R8 = 8    # Index  8
    JLINKARM_CM4_REG_R9 = 9    # Index  9
    JLINKARM_CM4_REG_R10 = 10   # Index 10
    JLINKARM_CM4_REG_R11 = 11   # Index 11
    JLINKARM_CM4_REG_R12 = 12   # Index 12
    JLINKARM_CM4_REG_R13 = 13   # Index 13: Pseudo reg! It needs to be mapped to SP_MSP or SP_PSP depending on current Controlregister
    JLINKARM_CM4_REG_R14 = 14   # Index 14
    JLINKARM_CM4_REG_R15 = 15   # Index 15
    JLINKARM_CM4_REG_XPSR = 16  # Index 16
    JLINKARM_CM4_REG_MSP = 17   # Index 17
    JLINKARM_CM4_REG_PSP = 18   # Index 18
    JLINKARM_CM4_REG_RAZ = 19   # Index 19: Reserved
    JLINKARM_CM4_REG_CFBP = 20  # Index 20: CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word)
    JLINKARM_CM4_REG_APSR = 21  # Index 21: Pseudo reg. (Part of XPSR)
    JLINKARM_CM4_REG_EPSR = 22  # Index 22: Pseudo reg. (Part of XPSR)
    JLINKARM_CM4_REG_IPSR = 23  # Index 23: Pseudo reg. (Part of XPSR)
    JLINKARM_CM4_REG_PRIMASK = 24           # Index 24: Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_BASEPRI = 25           # Index 25: Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_FAULTMASK = 26         # Index 26: Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_CONTROL = 27           # Index 27: Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_BASEPRI_MAX = 28       # Index 28: Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_IAPSR = 29             # Index 29: Pseudo reg. (Part of XPSR)
    JLINKARM_CM4_REG_EAPSR = 30             # Index 30: Pseudo reg. (Part of XPSR)
    JLINKARM_CM4_REG_IEPSR = 31             # Index 31: Pseudo reg. (Part of XPSR)
    JLINKARM_CM4_REG_FPSCR = 32             # Index 32
    JLINKARM_CM4_REG_FPS0 = 33              # Index 33
    JLINKARM_CM4_REG_FPS1 = 34              # Index 34
    JLINKARM_CM4_REG_FPS2 = 35              # Index 35
    JLINKARM_CM4_REG_FPS3 = 36              # Index 36
    JLINKARM_CM4_REG_FPS4 = 37              # Index 37
    JLINKARM_CM4_REG_FPS5 = 38              # Index 38
    JLINKARM_CM4_REG_FPS6 = 39              # Index 39
    JLINKARM_CM4_REG_FPS7 = 40              # Index 40
    JLINKARM_CM4_REG_FPS8 = 41              # Index 41
    JLINKARM_CM4_REG_FPS9 = 42              # Index 42
    JLINKARM_CM4_REG_FPS10 = 43             # Index 43
    JLINKARM_CM4_REG_FPS11 = 44             # Index 44
    JLINKARM_CM4_REG_FPS12 = 45             # Index 45
    JLINKARM_CM4_REG_FPS13 = 46             # Index 46
    JLINKARM_CM4_REG_FPS14 = 47             # Index 47
    JLINKARM_CM4_REG_FPS15 = 48             # Index 48
    JLINKARM_CM4_REG_FPS16 = 49             # Index 49
    JLINKARM_CM4_REG_FPS17 = 50             # Index 50
    JLINKARM_CM4_REG_FPS18 = 51             # Index 51
    JLINKARM_CM4_REG_FPS19 = 52             # Index 52
    JLINKARM_CM4_REG_FPS20 = 53             # Index 53
    JLINKARM_CM4_REG_FPS21 = 54             # Index 54
    JLINKARM_CM4_REG_FPS22 = 55             # Index 55
    JLINKARM_CM4_REG_FPS23 = 56             # Index 56
    JLINKARM_CM4_REG_FPS24 = 57             # Index 57
    JLINKARM_CM4_REG_FPS25 = 58             # Index 58
    JLINKARM_CM4_REG_FPS26 = 59             # Index 59
    JLINKARM_CM4_REG_FPS27 = 60             # Index 60
    JLINKARM_CM4_REG_FPS28 = 61             # Index 61
    JLINKARM_CM4_REG_FPS29 = 62             # Index 62
    JLINKARM_CM4_REG_FPS30 = 63             # Index 63
    JLINKARM_CM4_REG_FPS31 = 64             # Index 64
    JLINKARM_CM4_REG_DWT_CYCCNT = 65        # Index 65
    JLINKARM_CM4_REG_MSP_NS = 66            # New reg.
    JLINKARM_CM4_REG_PSP_NS = 67            # New reg.
    JLINKARM_CM4_REG_MSP_S = 68             # New reg.
    JLINKARM_CM4_REG_PSP_S = 69             # New reg.
    JLINKARM_CM4_REG_MSPLIM_S = 70          # New reg.
    JLINKARM_CM4_REG_PSPLIM_S = 71          # New reg.
    JLINKARM_CM4_REG_MSPLIM_NS = 72         # New reg.
    JLINKARM_CM4_REG_PSPLIM_NS = 73         # New reg.
    JLINKARM_CM4_REG_CFBP_S = 74            # New reg.
    JLINKARM_CM4_REG_CFBP_NS = 75           # New reg.
    JLINKARM_CM4_REG_PRIMASK_NS = 76        # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_BASEPRI_NS = 77        # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_FAULTMASK_NS = 78      # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_CONTROL_NS = 79        # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_BASEPRI_MAX_NS = 80    # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_PRIMASK_S = 81         # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_BASEPRI_S = 82         # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_FAULTMASK_S = 83       # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_CONTROL_S = 84         # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_BASEPRI_MAX_S = 85     # Pseudo reg. (Part of CFBP)
    JLINKARM_CM4_REG_MSPLIM = 86            # Either real or pseudo reg depending on if security extensions are implemented or not
    JLINKARM_CM4_REG_PSPLIM = 87            # Either real or pseudo reg depending on if security extensions are implemented or not
    JLINKARM_CM4_REG_MAX = 100
    # 其他寄存器可按需添加

# 示例寄存器索引
reg_indices = [
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R0,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R1,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R2,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R3,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R4,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R5,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R6,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R7,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R8,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R9,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R10,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R11,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R12,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R13,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R14,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_R15,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_XPSR,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_MSP,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_PSP,
    #JLINKARM_CM4_REG.JLINKARM_CM4_REG_RAZ,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_CFBP,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_APSR,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_EPSR,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_IPSR,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_PRIMASK,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_BASEPRI,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FAULTMASK,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_CONTROL,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_BASEPRI_MAX,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_IAPSR,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_EAPSR,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_IEPSR,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPSCR,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS0,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS1,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS2,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS3,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS4,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS5,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS6,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS7,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS8,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS9,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS10,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS11,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS12,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS13,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS14,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS15,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS16,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS17,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS18,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS19,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS20,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS21,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS22,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS23,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS24,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS25,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS26,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS27,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS28,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS29,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS30,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_FPS31,
    JLINKARM_CM4_REG.JLINKARM_CM4_REG_DWT_CYCCNT,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_MSP_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_PSP_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_MSP_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_PSP_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_MSPLIM_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_PSPLIM_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_MSPLIM_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_PSPLIM_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_CFBP_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_CFBP_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_PRIMASK_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_BASEPRI_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_FAULTMASK_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_CONTROL_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_BASEPRI_MAX_NS,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_PRIMASK_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_BASEPRI_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_FAULTMASK_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_CONTROL_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_BASEPRI_MAX_S,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_MSPLIM,
    # JLINKARM_CM4_REG.JLINKARM_CM4_REG_PSPLIM,
]

# 定义设备系列常量
JLINKARM_DEV_FAMILY = {
    "AUTO": 0,
    "CM1": 1,
    "CF": 2,
    "CM3": 3,
    "SIM": 4,
    "XSCALE": 5,
    "CM0": 6,
    "ARM7": 7,
    "CORTEX_A8": 8,
    "ARM9": 9,
    "ARM10": 10,
    "ARM11": 11,
    "CORTEX_R4": 12,
    "RX": 13,
    "CM4": 14,
    "CORTEX_A5": 15,
    "POWER_PC": 16,
    "MIPS": 17,
    "EFM8": 18,
    "RISC_V": 19,
    "CORTEX_AR_ARMV8": 0x14,
    "BT5511": 0x15,
    "ANY": 255
}

def identify_device_family(device_family):
    if device_family == JLINKARM_DEV_FAMILY["ARM7"]:
        print("ARM7 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["ARM9"]:
        print("ARM9 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["ARM11"]:
        print("ARM11 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CM3"]:
        print("Cortex-M3 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CM1"]:
        print("Cortex-M1 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CF"]:
        print("ColdFire identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["SIM"]:
        print("Simulator identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["XSCALE"]:
        print("XScale identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CM0"]:
        print("Cortex-M0 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CORTEX_A8"]:
        print("Cortex-A8 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["ARM10"]:
        print("ARM10 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CORTEX_R4"]:
        print("Cortex-R4 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["RX"]:
        print("Renesas RX core identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CM4"]:
        print("Cortex-M4 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CORTEX_A5"]:
        print("Cortex-A5 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["POWER_PC"]:
        print("PowerPC identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["MIPS"]:
        print("MIPS architecture identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["EFM8"]:
        print("SiLabs EFM8 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["RISC_V"]:
        print("RISC-V identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["CORTEX_AR_ARMV8"]:
        print("ARMv8A/R identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["BT5511"]:
        print("Microchip BT5511 identified.")
        return 0  # O.K.
    elif device_family == JLINKARM_DEV_FAMILY["ANY"]:
        print("Any device family identified.")
        return 0  # O.K.
    else:
        print("Unknown device family.")
        return -1  # Error

# 定义处理函数
def error_warn_handler(message):
    # 将 C 字符串转换为 Python 字符串
    message_str = message.decode('utf-8')
    print("Error/Warning:", message_str)
    
# 定义日志处理函数
def log_handler(message):
    message_str = message.decode('utf-8')
    print("Log:", message_str)    
    
# 定义错误处理函数
def error_handler(message):
    message_str = message.decode('utf-8')
    print("Error:", message_str)            

def read_memory(jlink, start_addr, num_bytes, access_width=0):
    # 创建一个缓冲区来存储读取的数据
    buffer_type = (ctypes.c_ubyte * num_bytes)()  # 使用 c_ubyte 数组
    buffer_address = ctypes.cast(buffer_type, ctypes.c_void_p)  # 获取缓冲区的地址

    # 调用 JLINKARM_ReadMemEx 函数
    result = jlink.JLINKARM_ReadMemEx(start_addr, num_bytes, buffer_address, access_width)

    # 判断结果
    if result > 0:
        print(f"Reading {num_bytes} bytes from addr 0x{start_addr:X}... O.K.")
        return buffer_type  # 返回读取到的缓冲区
    else:
        raise JLinkException(f"Memory read failed with error code: {result}") # 建议引发异常，而不是返回 None

def save_to_file(buffer, file_path):
    """将缓冲区内容保存到文件"""
    with open(file_path, 'wb') as f:
        f.write(buffer)  # 写入二进制数据
    print(f"Data has been saved to '{file_path}'.")            

def run_jlink_script(dll_path, axf_path, start_address, length, device_name):
    """
    运行 JLink 脚本，连接到设备，读取寄存器和内存，并将结果保存到文件。
    """

    try:
        # 加载 JLinkARM DLL
        jlink = ctypes.CDLL(dll_path)
        #所有 JLink 函数的 restype 和 argtypes 配置
        jlink.JLINKARM_OpenEx.restype = ctypes.c_char_p
        jlink.JLINKARM_Open.restype = ctypes.c_char_p
        jlink.JLINKARM_GetFirmwareString.argtypes = [ctypes.c_char_p, ctypes.c_int]
        jlink.JLINKARM_GetHardwareVersion.restype = ctypes.c_int
        jlink.JLINKARM_GetSN.restype = ctypes.c_int
        jlink.JLINKARM_GetFeatureString.argtypes = [ctypes.c_char_p]  # Fix: Add argtypes
        jlink.JLINKARM_SelectUSB.restype = None  # Or appropriate return type
        jlink.JLINK_GetpFunc.restype = ctypes.c_void_p
        jlink.JLINKARM_DEVICE_GetIndex.argtypes = [ctypes.c_char_p]
        jlink.JLINKARM_DEVICE_GetInfo.restype = ctypes.c_int
        jlink.JLINKARM_ConfigJTAG.argtypes = [ctypes.c_uint, ctypes.c_uint]
        jlink.JLINKARM_ExecCommand.restype = ctypes.c_int
        jlink.JLINKARM_ExecCommand.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
        jlink.JLINKARM_GetEmuCapsEx.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_int]
        jlink.JLINKARM_TIF_GetAvailable.argtypes = [ctypes.POINTER(ctypes.c_uint32)]
        jlink.JLINKARM_TIF_Select.argtypes = [ctypes.c_int]
        jlink.JLINKARM_IsConnected.restype = ctypes.c_int
        jlink.JLINKARM_SetSpeed.argtypes = [ctypes.c_uint32]
        jlink.JLINKARM_GetIdData.argtypes = [ctypes.POINTER(JTAG_ID_DATA)]
        jlink.JLINKARM_HasError.restype = ctypes.c_int
        jlink.JLINKARM_CORE_GetFound.restype = ctypes.c_int
        jlink.JLINKARM_Core2CoreName.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int]
        jlink.JLINKARM_Halt.restype = ctypes.c_int
        jlink.JLINKARM_GetDeviceFamily.restype = ctypes.c_int
        jlink.JLINKARM_GetDebugInfo.restype = ctypes.c_int
        jlink.JLINKARM_GetDebugInfo.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_uint32)]
        jlink.JLINKARM_ReadRegs.restype = ctypes.c_int
        jlink.JLINKARM_ReadRegs.argtypes = [ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.c_void_p, ctypes.c_int]
        jlink.JLINKARM_ReadMemEx.argtypes = [ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32]
        jlink.JLINKARM_ReadMemEx.restype = ctypes.c_int
        jlink.JLINKARM_IsOpen.restype = ctypes.c_int
        jlink.JLINKARM_Close.restype = None  # Or appropriate return type
        jlink.JLINKARM_Connect.restype = ctypes.c_int  # Ensure correct return type for JLINKARM_Connect

        # 设置 JLINKARM_GetDLLVersion 的返回类型
        jlink.JLINKARM_GetDLLVersion.restype = ctypes.c_int
        # 获取 DLL 版本号
        Ver = jlink.JLINKARM_GetDLLVersion()
        # 解析主版本号、次版本号和补丁字母
        major = Ver // 10000                  # 主版本号
        minor = (Ver // 100) % 100            # 次版本号
        patch_letter = chr(ord('a') + Ver % 100 - 1) if Ver % 100 > 0 else ''  # 补丁字母
        # 打印出格式化的版本信息
        print(f"J-Link DLL Version: {major}.{minor:02}{patch_letter}")
        # 设置 JLINKARM_GetCompileDateTime 的返回类型为 c_char_p
        jlink.JLINKARM_GetCompileDateTime.restype = ctypes.c_char_p
        # 调用函数并获取返回值
        compile_date_time = jlink.JLINKARM_GetCompileDateTime()
        # 将 C 字符串转换为 Python 字符串
        compile_date_time_str = compile_date_time.decode('utf-8')  # 如果使用其他编码，可以相应调整
        # 打印返回的编译日期时间
        print("Compile Date and Time:", compile_date_time_str)
        
        # --- 错误和日志处理函数 ---
        ErrorWarnHandlerType = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
        LogHandlerType = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
        # 创建处理函数的函数指针
        handler_pointer = ErrorWarnHandlerType(error_warn_handler)
        # 将函数指针传递给 JLINKARM_SetWarnOutHandler
        jlink.JLINKARM_SetWarnOutHandler(handler_pointer)
        # 定义日志处理函数的原型
        LogHandlerType = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
        # 创建处理函数的函数指针
        log_handler_pointer = LogHandlerType(log_handler)
        error_handler_pointer = LogHandlerType(error_handler)
        # 调用 JLINKARM_OpenEx 并传入函数指针
        result = jlink.JLINKARM_OpenEx(log_handler_pointer, error_handler_pointer)
        # 将返回值转换为 Python 字符串
        result_str = result.decode('utf-8') if result else "No result"
        print("JLINKARM_OpenEx result:", result_str)
        # 调用函数并获取返回值
        test_open_log = jlink.JLINKARM_Open()
        # 检查返回值是否为 NULL
        if test_open_log is None:
            print("Connecting to J-Link via USB...O.K.")  # 仅在成功时打印相关字符串
        else:
            # 这里可以处理 test_open_log
            test_open_log_str = ctypes.cast(test_open_log, ctypes.c_char_p).value.decode('utf-8')
            print("Log String:", test_open_log_str)  # 仅在成功时打印相关字符串
        # 创建一个字符数组的缓冲区，大小为 256 字节
        firmware_string_buffer = ctypes.create_string_buffer(256)
        # 调用 JLINKARM_GetFirmwareString，传入字符数组和大小
        jlink.JLINKARM_GetFirmwareString(firmware_string_buffer, 256)
        # 从缓冲区获取固件字符串
        firmware_string = firmware_string_buffer.value.decode('utf-8')  # 解码为 Python 字符串
        # 打印固件字符串
        print("Firmware:", firmware_string)
        # 调用函数并获取返回值
        version = jlink.JLINKARM_GetHardwareVersion()
        # 解析主版本号、次版本号和补丁字母
        major = version // 10000                  # 主版本号
        minor = (version // 100) % 100            # 次版本号
        # 打印出格式化的版本信息
        print(f"J-Link Hardware Version: V{major}.{minor:02}")
        # 调用JLINKARM_GetSN获取并打印J-Link序列号
        print("S/N:", jlink.JLINKARM_GetSN())
        # 创建一个字符数组的缓冲区，大小为 256 字节
        firmware_string_buffer = ctypes.create_string_buffer(256)
        jlink.JLINKARM_GetFeatureString(firmware_string_buffer)
        firmware_string = firmware_string_buffer.value.decode('utf-8')  # 解码为 Python 字符串
        print("License(s):", firmware_string)
        jlink.JLINKARM_EMU_GetProductId.restype = ctypes.c_int
        print("JLINKARM_EMU_GetProductId:", jlink.JLINKARM_EMU_GetProductId())
        jlink.JLINKARM_SelectUSB()
        # 使用 ctypes 定义一个函数指针类型
        ErrorWarnHandlerType = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
        # 创建处理函数的函数指针
        handler_pointer = ErrorWarnHandlerType(error_warn_handler)
        # 将函数指针传递给 JLINKARM_SetWarnOutHandler
        jlink.JLINKARM_SetWarnOutHandler(handler_pointer)
        # 定义日志处理函数的原型
        # 假设处理函数的原型是 void (*handler)(const char*)
        LogHandlerType = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
        # 创建处理函数的函数指针
        log_handler_pointer = LogHandlerType(log_handler)
        error_handler_pointer = LogHandlerType(error_handler)
        # 调用 JLINKARM_OpenEx 并传入函数指针
        result = jlink.JLINKARM_OpenEx(log_handler_pointer, error_handler_pointer)
        # 将返回值转换为 Python 字符串
        result_str = result.decode('utf-8') if result else "No result"
        print("JLINKARM_OpenEx result:", result_str)
        print("JLINK_GetpFunc:", jlink.JLINK_GetpFunc(4))
        # 定义设备名称
        device_name = "GD32F303ZE"
        # 将 Python 字符串转换为 C 字符串（使用 UTF-8 编码）
        c_device_name = ctypes.create_string_buffer(device_name.encode('utf-8'))
        # 调用函数并获取返回值
        device_index = jlink.JLINKARM_DEVICE_GetIndex(c_device_name)
        # 打印设备索引
        print("Device Index for {}: {}".format(device_name, device_index))
        num_devices = jlink.JLINKARM_DEVICE_GetInfo(-1, None)
        # 打印支持的设备数量
        print("Following {} devices are supported:".format(num_devices))
        # 定义参数
        param1 = ctypes.c_uint(0xFFFFFFFF)
        param2 = ctypes.c_uint(0xFFFFFFFF)
        # 调用 JLINKARM_ConfigJTAG 函数
        result = jlink.JLINKARM_ConfigJTAG(param1, param2)
        # 创建 acCmd 和 acOut 的缓冲区
        acCmd = ctypes.create_string_buffer(b"Device = GD32F303ZE", 256)
        acOut = ctypes.create_string_buffer(256)
        # 调用 JLINKARM_ExecCommand
        r = jlink.JLINKARM_ExecCommand(acCmd, acOut, ctypes.c_int(len(acOut)))
        if acOut.value == b"":  # acOut[0] == 0 表示命令成功执行，没有错误信息
            print("Command executed successfully!")
            print("Return value of command:", r)
        else:
            print("Failed to execute command!")
            print("Output:", acOut.value.decode('utf-8'))
            
        # 定义所需的常量
        JLINKARM_CAP_EX_HW_JTAG_WRITE = 32  # 
        # 创建一个 32 字节的缓冲区 ab，用于接收 JLINKARM_GetEmuCapsEx 的返回值
        ab = (ctypes.c_uint8 * 32)()
        # 调用 JLINKARM_GetEmuCapsEx，直接传递 ab 数组
        jlink.JLINKARM_GetEmuCapsEx(ab, ctypes.c_int(len(ab)))
        # 计算 Byte 和 Bit
        CapEx = JLINKARM_CAP_EX_HW_JTAG_WRITE
        Byte = CapEx >> 3
        Bit = CapEx & 7

        # 检查指定的功能是否受支持
        if ab[Byte] & (1 << Bit):
            print("Emulator supports the requested capability.")
            result = 1
        else:
            print("Requested capability is not supported by the emulator.")
            result = 0

        # 输出结果
        print("Result:", result)
        print("========================")
                
        # --- 连接到设备 ---
        # 获取可用的调试接口
        mask = ctypes.c_uint32()
        jlink.JLINKARM_TIF_GetAvailable(ctypes.byref(mask))
        print("Interface available:",mask)
        # 检查 SWD 是否可用
        if mask.value & (1 << 1):
            # 选择 SWD 接口
            jlink.JLINKARM_TIF_Select(1)
            
            print("SWD interface selected.")
            if not jlink.JLINKARM_IsConnected():
                print("JTAG is connected")
            else:
                print("JTAG is not connected")
            
            print("SetSpeed(4000)")
            jlink.JLINKARM_SetSpeed(4000)
            print("====JTAG Connectting====")


            # 调用JLINKARM_Connect
            jlink.JLINKARM_Connect()
        else:
            print("SWD interface is not supported by connected J-Link!")

        # 创建 JTAG_ID_DATA 结构体实例
        id_data = JTAG_ID_DATA()
        # 调用函数
        jlink.JLINKARM_GetIdData(ctypes.byref(id_data))

        # 打印结果
        print(f"Number of Devices: {id_data.NumDevices}")
        print(f"Scan Length: {id_data.ScanLen}")
        for i in range(id_data.NumDevices):
            print(f"Device ID[{i}]: 0x{id_data.aId[i]:X}")
            print(f"Scan Length[{i}]: {id_data.aScanLen[i]}")
            print(f"IR Read[{i}]: {id_data.aIrRead[i]}")
            print(f"Scan Read[{i}]: {id_data.aScanRead[i]}")
        #JLINK_GetMemZones 没处理

        #HasError
        print("DLL internal error state:",jlink.JLINKARM_HasError())
        #CORE_GetFound
        CORE = jlink.JLINKARM_CORE_GetFound()
        print("CORE_GetFound:",CORE)
        # 创建一个字符数组的缓冲区，大小为 256 字节
        core_string_buffer = ctypes.create_string_buffer(50)
        jlink.JLINKARM_Core2CoreName(CORE,core_string_buffer,50)
        # 解码为 Python 字符串
        print("Core Name:", core_string_buffer.value.decode('utf-8'))
        #Halt
        print("Halt:", jlink.JLINKARM_Halt())
        #Get Family
        print("DeviceFamily:", jlink.JLINKARM_GetDeviceFamily())
        CORE = jlink.JLINKARM_CORE_GetFound()
        identify_device_family(jlink.JLINKARM_GetDeviceFamily())
        # 定义常量
        JLINKARM_ROM_TABLE_ADDR_INDEX = 0x100  # 根据你的实际值进行调整
        # 准备参数
        ROMTableAddr = ctypes.c_uint32()  # 创建一个U32类型的变量来接收结果
        index = JLINKARM_ROM_TABLE_ADDR_INDEX  # 使用预定义的索引

        # 调用JLINKARM_GetDebugInfo
        r = jlink.JLINKARM_GetDebugInfo(index, ctypes.byref(ROMTableAddr))  # 通过引用传递地址

        # 根据返回值进行输出
        if r == 0:
            print(f"ROMTableAddr = 0x{ROMTableAddr.value:X}")  # 打印地址
        else:
            print(f"No debug information for index 0x{index:04X} available on this CPU.")

        # --- 读取寄存器 ---
        # 定义ctypes数组，将枚举值直接放入其中
        num_indices = len(reg_indices)
        print("num:",num_indices)
        #reg_indices_array = (ctypes.c_uint32 * num_indices)(*map(lambda reg: reg.value, reg_indices))
        # 获取寄存器索引的数量
        reg_indices_values = []
        for reg in reg_indices:
            try:
                reg_value = reg.value  # 获取寄存器值
                reg_indices_values.append(reg_value)
            except AttributeError:
                print(f"Warning: The register object does not have 'value' attribute: {reg}")
        # 创建 ctypes 数组，存储寄存器索引值
        reg_indices_array = (ctypes.c_uint32 * num_indices)(*reg_indices_values)
        # 定义aRegData数组，假设我们需要读取5个寄存器值
        aRegData = (ctypes.c_uint32 * (num_indices))()
        # 调用JLINKARM_ReadRegs，传入数组首地址
        reg_data = jlink.JLINKARM_ReadRegs(reg_indices_array, aRegData, None, num_indices)

        print("************************ Register information ************************")

        # output_lines = []
        # for i, reg_index in enumerate(reg_indices):
        #     try:
        #         reg_value = aRegData[i]  # 获取对应的寄存器值
        #         reg_name = reg_index.name.replace('JLINKARM_CM4_REG_', '')  # 去掉前缀
        #         output_lines.append(f"{reg_name:<15} = {reg_value:08X}")  # 使用左对齐
        #     except IndexError as e:
        #         print(f"Index error for reg_index {reg_index}: {e}")
        #     except Exception as e:
        #         print(f"An error occurred while processing index {i}: {e}")

        # 输出结果
        output_lines = []
        for i, reg_index in enumerate(reg_indices):
            reg_value = aRegData[i]  # 获取对应的寄存器值
            reg_name = reg_index.name.replace('JLINKARM_CM4_REG_', '')  # 去掉前缀
            output_lines.append(f"{reg_name:}={reg_value:08X}")  # 使用左对齐
        # print("output_lines:", output_lines)
        # 每4个元素后换行
        formatted_lines = []
        for i in range(0, len(output_lines), 4):
            # 将每四个元素拼接成一行
            line = ', '.join(output_lines[i:i + 4])  
            formatted_lines.append(line)  # 添加到格式化后的行列表中
            
        # 定义registers.txt要保存的文件路径
        registers_txt_path = os.path.join(os.path.dirname(axf_path), 'registers.txt')
        registers_txt_path = os.path.normpath(registers_txt_path)

        reg_info = formatted_lines
        # 添加SP和PC的打印信息
        sp_value = f"{aRegData[JLINKARM_CM4_REG.JLINKARM_CM4_REG_R13.value]:08X}"
        pc_value = f"{aRegData[JLINKARM_CM4_REG.JLINKARM_CM4_REG_R15.value]:08X}"
        lr_value = f"{aRegData[JLINKARM_CM4_REG.JLINKARM_CM4_REG_R14.value]:08X}"
        reg_info_line = f"PC = {pc_value}, SP(R13) = {sp_value}, R14(LR) = {lr_value}"
        # 将组合好的行插入到 reg_info 列表的开头
        reg_info.insert(0, reg_info_line)
        # 将 formatted_lines 内容保存到文件
        with open(registers_txt_path, 'w') as file:
            for line in reg_info:
                file.write(line + '\n')  # 每行后添加换行符

        print(f"Formatted lines have been saved to '{registers_txt_path}'.")               
        print('=' * len(formatted_lines[1]))   
        # 每4行后添加分隔符，分隔符的长度与上一行相同
        for i in range(4, len(formatted_lines)+5, 5):  # 从第0行开始，每5行插入一次分隔符
            previous_line_length = len(formatted_lines[i - 1])  # 获取上一行的字符数
            separator = '-' * previous_line_length  # 根据上一行的长度生成分隔符
            formatted_lines.insert(i, separator)  # 在适当的位置插入分隔符
        # 通过换行连接结果
        output_string = '\n'.join(formatted_lines)  # 每行的结果通过换行连接
        print(output_string)
        print('=' * previous_line_length)

        # --- 读取并保存内存 ---
        start_address = int(start_address, 0)
        length = int(length, 0)
        buffer = read_memory(jlink, start_address, length) # 注意这里传入 jlink 对象
        if buffer:
            save_to_file(buffer, os.path.normpath(os.path.join(os.path.dirname(axf_path), "ram.bin")))

        # --- 关闭 J-Link 连接 ---
        jlink.JLINKARM_Close()
        print("J-Link closed")
    except JLinkException as e:
        raise  # 重新引发 JLink 异常
    except Exception as e:
        raise  # 重新引发其他异常
